package org.springframe.aop;

import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
* @package  org.springframe.aop
* @classname JdkDynamicAopProxy
* @description 通过JDK动态代理生成代理对象
* @version 1.0
* @author luoweiwei
* @date  2021-04-25 13:21:12
*/
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {

    private Object target;

    private  Class<?>[] proxiedInterfaces;

    private Set<Class> aspectDeclaredClass;

    private Map<Class,Object> aspectMap = new HashMap<>();

    public JdkDynamicAopProxy(Object target, Class<?>[] proxiedInterfaces, Set<Class> aspectDeclaredClass) {
        this.target = target;
        this.proxiedInterfaces = proxiedInterfaces;
        this.aspectDeclaredClass = aspectDeclaredClass;
    }

    @Override
    public Object getProxy() throws Exception{
        return  getProxy(this.getClass().getClassLoader());
    }

    @Override
    public Object getProxy(ClassLoader classLoader) throws Exception {
        return Proxy.newProxyInstance(classLoader,proxiedInterfaces,this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //调用方法前
        try {
            for (Class declaredClass : aspectDeclaredClass) {
                Object obj;
                if((obj = aspectMap.get(declaredClass))==null){
                    obj= declaredClass.getDeclaredConstructor().newInstance();
                    aspectMap.put(declaredClass,obj);
                }
                Method[] method1 = declaredClass.getDeclaredMethods();
                for (Method method2 : method1) {
                    if(method2.getName().equals("before")){
                        method2.setAccessible(true);
                        method2.invoke(obj,method.getName(),args);
                    }
                }

            }
            Object ret = method.invoke(target,args);
            //调用方法后
            for (Class declaredClass : aspectDeclaredClass) {
                Object obj = aspectMap.get(declaredClass);
                Method[] method1 = declaredClass.getDeclaredMethods();
                for (Method method2 : method1) {
                    if(method2.getName().equals("after")){
                        method2.setAccessible(true);
                        method2.invoke(obj,method.getName(),args);
                    }
                }
            }
            return ret;
        }  catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
}
